/**
 @description 用于前端防抖与权限控制
 @author jzyong(沈健汉)
 @date 2020-10-23
 */
(function (global, factory) {
    typeof exports === 'object' && typeof module !== 'undefined' ?
        module.exports = factory() :
        typeof define === 'function' && define.amd ? define(factory) :
            (global = global || self, global.AntiShakeAndPer = factory());

})(this, function () {
    'use strict';

    /**
     * @description 基础配置
     * @param onStart 事件开始触发
     * @param onEnd 事件结束触发
     * @param onError 事件出错触发(
     *      当连续触发事件，上一事件未结束，将会触发此事件，传入参数：1
     *      没有权限，传入参数：2
     * )
     * @param autoRestoreTime
     * @constructor
     */
    var AntiShakeAndPerConfig = function (onStart, onEnd, onError, autoRestoreTime = 3000) {
        this.onStart = onStart
        this.onEnd = onEnd
        this.onError = onError
        this.onStart = onStart
        this.autoRestoreTime = autoRestoreTime
    }

    AntiShakeAndPerConfig.prototype.ERROR_CODE_NOT_END = 1 // 上一事件未结束
    AntiShakeAndPerConfig.prototype.ERROR_CODE_NOT_PER = 2 // 没有权限


    /**
     *
     * @param {Config} AntiShakeAndPerConfig 配置对象
     * @param {Array<String>>} permissions 权限列表，里面是字符串
     * @constructor
     */
    var AntiShakeAndPer = function (AntiShakeAndPerConfig, permissions = []) {
        this.isRun = false // 锁
        this.permissions = permissions // 权限列表
        if (!AntiShakeAndPerConfig) {
            this.config = new AntiShakeAndPerConfig(
                function () {
                    console.log('AntiShakeAndPer: start')
                },
                function () {
                    console.log('AntiShakeAndPer: end')
                },
                function (type) {
                    switch (type) {
                        case 1:
                            console.log('AntiShakeAndPer: error, msg: 上一事件还没调用结束方法，当前方法将不会运行')
                            break
                        case 2:
                            console.log('AntiShakeAndPer: error, msg: 没有权限')
                            break
                    }
                },
            )
        } else {
            this.config = AntiShakeAndPerConfig
        }

        /**
         * 回调函数
         */
        this._done = function () {
            this.config.onEnd()
            this.isRun = false
        }

        /**
         * @description 是否拥有此权限
         * @param {Array|String} per 权限，当是数组时，指满足其中一个即可，当是字符串时，拥有此权限即可
         * @param {Boolean} all 数组时需要满足全部
         */
        this.hasPer = function (per, all = false) {
            // 如果权限表为空，直接返回true
            if (this.permissions.length === 0 || !per) return true

            if (Array.isArray(per)) {
                if (all) {
                    // 全部权限都需要有
                    for (var i = 0; i < per.length; i++) {
                        // 有一个不存在，返回false
                        if (this.permissions.indexOf(per[i]) === -1) return false
                    }
                    return true
                } else {
                    // 只需有一个即可
                    for (var i = 0; i < per.length; i++) {
                        // 有一个不存在，返回false
                        if (this.permissions.indexOf(per[i]) >= 0) return true
                    }
                    return false
                }
            } else {
                if (this.permissions.indexOf(per) === -1) return false
                return true
            }
        }

        /**
         * @description 运行异步函数
         * @param {Function} fun 执行函数
         * @param {Boolean} enable 是否启用同步功能
         * @param {Array<String>|String} per 所需权限
         */
        this.run = function (fun, per = '', enable = true) {
            // 先验证有没有权限
            if (!this.hasPer(per)) {
                this.config.onError(this.config.ERROR_CODE_NOT_PER)
                return
            }

            // 验证是否在执行需要同步的事件
            if (this.isRun) {
                this.config.onError(this.config.ERROR_CODE_NOT_END)
                return
            }

            this.config.onStart()

            /**
             * 计时执行时间
             */
            var interval = setTimeout(function () {
                if (this.isRun) {
                    this.config.onError(3)
                    this.isRun = false
                    console.error('请在合适的地方对事件执行结束操作')
                }
                clearTimeout(interval)
            }.bind(this), this.config.autoRestoreTime)

            // 开始执行操作
            if (enable) this.isRun = true // 上锁
            fun(this._done.bind(this))
        }
    }

    return {
        AntiShakeAndPerConfig,
        AntiShakeAndPer
    }
})
